import base64
from ctypes import c_uint32, c_int32

def uint(n):return c_uint32(n).value
def int32(n):return c_int32(n).value

def _MX(sum, y, z, p, e, k):
    return uint((int32(z >> 5) ^ int32(y << 2)) + (int32(y >> 3) ^ int32(z << 4)) ^ (int32(sum) ^ int32(y)) + (int32(k[int(p & 3) ^ int(e)]) ^ int32(z)))
def _Encrypt(v, k):
    index = len(v) - 1
    z = uint(v[index])
    sum = 0
    num = 6 + 52 // (index + 1)
    while 0<num :
        num -= 1
        sum += 2654435769
        e = sum >> 2 & 3
        for p in range(0, index):
            y = v[p + 1]
            v[p] = uint(v[p] + _MX(sum, y, z, p, e, k))
            z = v[p]
        p += 1
        y1 = v[0]
        v[index] = uint(v[index] + _MX(sum, y1, z, p, e, k))
        z = v[index]
    return v
def _Decrypt(v, k):
    index = len(v) - 1
    y = v[0]
    sum = uint(uint(6 + 52 // (index + 1)) * 2654435769)
    while sum != 0:
        e = sum >> 2 & 3
        for p in range(index, -1, -1):
            if p==0:break
            z = v[p - 1]
            v[p] = uint(v[p] - _MX(sum, y, z, p, e, k))
            y = v[p]
        z1 = v[index]
        v[0] = uint(v[0] - _MX(sum, y, z1, p, e, k))
        y = v[0]
        sum = uint(sum - 2654435769)
    return v
def _ToUInt32Array(data,includeLength):
    length1 = len(data)
    length2 = ( length1 >> 2 if (length1 & 3) == 0 else (length1 >> 2) + 1)
    if includeLength:
        uint32Array = [0] * (length2+1)
        uint32Array[length2] = length1
    else:
        uint32Array = [0] * length2
    for index in range(length1):
        uint32Array[index >> 2] |= data[index] << ((index & 3) << 3)
    return uint32Array
def _ToByteArray(data, include_length):
    length = len(data) << 2
    if include_length:
        num1 = data[-1]
        num2 = length - 4
        if not(num1 < num2 - 3 or num1 > num2):
            length = num1
    byte_array = [0] * length
    for index in range(length):
        byte_array[index] = (data[index >> 2] >> ((index & 3) << 3))%256
    return byte_array
def _FixKey(key):
    if len(key) == 16:
        return key
    elif len(key) < 16:
        return key + '\0'*(16-len(key))
    else:
        return key[:16]
    

def encrypt(data:str,key:str)->str:
    '''加密utf8字符串
    :param data:utf8字符串明文
    :param key:ascii字符串秘钥
    :return:base64字符串密文
    '''
    # 加密预处理
    key_numls = list(_FixKey(key).encode("ascii"))
    plain_numls = list(data.encode())
    # 加密
    enc_numls = _Encrypt(_ToUInt32Array(plain_numls, True), _ToUInt32Array(key_numls, False))
    enc_bytels = _ToByteArray(enc_numls, False)
    return base64.b64encode(bytes(enc_bytels))

def decrypt(data:str,key:str)->str:
    '''解密base64字符串
    :param data:base64字符串密文
    :param key:ascii字符串秘钥
    :return:utf8字符串明文
    '''
    # 解密预处理
    key_numls = list(_FixKey(key).encode("ascii"))
    cipher_numls = list(base64.b64decode( data ))
    # 解密
    dec_numls = _Decrypt(_ToUInt32Array(cipher_numls,False), _ToUInt32Array(key_numls,False))
    dec_bytels = _ToByteArray(dec_numls,True)
    return bytes(dec_bytels).decode()

